<?php

namespace Dreamcat\Class2Array\Cases;

use DreamCat\Array2Class\TransImpl\CamelCase2UnderLine;
use Dreamcat\Class2Array\DemoClass\Child;
use Dreamcat\Class2Array\DemoClass\EmptyClass;
use Dreamcat\Class2Array\DemoClass\Jsonabled;
use Dreamcat\Class2Array\DemoClass\ParentClass;
use Dreamcat\Class2Array\DemoClass\Pojo;
use Dreamcat\Class2Array\Enum\JsonEncodeOption;
use Dreamcat\Class2Array\Exception\EncodeError;
use Dreamcat\Class2Array\Impl\Class2Json;
use Dreamcat\Class2Array\Impl\DefaultJsonValueFixer;
use Dreamcat\Class2Array\JsonValueFixer;
use PHPUnit\Framework\TestCase;

/**
 * Class2Json的测试类
 * @author vijay
 */
class Class2JsonTest extends TestCase
{
    /**
     * 常规测试
     * @param mixed $input 输入的数据
     * @param string $expected 预期的输入
     * @param ?JsonValueFixer $fixer json数据修正器
     * @return void
     * @dataProvider normalData
     */
    public function testNormal(mixed $input, string $expected, JsonValueFixer $fixer = null)
    {
        $encoder = new Class2Json();

        if ($fixer) {
            $encoder->setFixer($fixer);
        }

        $output = $encoder->jsonEncode($input);
        self::assertEquals($expected, $output, "校验未通过");
    }

    /**
     * 常规测试的测试数据
     * @return array
     */
    public static function normalData(): array
    {
        return [
            [
                new Child(10, "pv2", "pv3", "abc"),
                '{"cf1":"abc","sharePrivate":"pv2::child","share_public":"pv3::child"}',
                new DefaultJsonValueFixer(),
            ],
            [
                (function () {
                    $obj = new ParentClass([], true, new EmptyClass());
                    /** @noinspection PhpUndefinedFieldInspection */
                    /** @noinspection PhpDynamicFieldDeclarationInspection */
                    $obj->ext = [
                        new Jsonabled(),
                        new Jsonabled(38),
                        null,
                    ];
                    return $obj;
                })(),
                '{"cf1":[],"sharePrivate":true,"sharePublic":{},"ext":[null,{"count":38},null]}',
            ],
            [
                new Pojo(),
                '{"demoString":null}'
            ],
        ];
    }

    /**
     * 测试异常场景
     * @param mixed $input 编码会报错的数据
     * @param string $expectedClass
     * @param string $expectedMsg
     * @param int $expectedCode
     * @return void
     * @dataProvider errorData
     */
    public function testError(mixed $input, string $expectedClass, string $expectedMsg, int $expectedCode)
    {
        $this->expectException($expectedClass);
        $this->expectExceptionMessage($expectedMsg);
        $this->expectExceptionCode($expectedCode);

        (new Class2Json())->jsonEncode($input);
    }

    /**
     * 异常场景下的测试数据
     * @return array
     */
    public function errorData(): array
    {
        return [
            [
                fopen(__FILE__, "r"),
                EncodeError::class,
                "Type is not supported",
                8,
            ],
        ];
    }

    /**
     * 测试 option 的配置
     * @return void
     */
    public function testOption()
    {
        $encoder = new Class2Json();
        $encoder->enableOption(JsonEncodeOption::JSON_FORCE_OBJECT());
        self::assertEquals(JSON_FORCE_OBJECT, $encoder->getJsonOption());

        $encoder->enableOptions([
            JsonEncodeOption::JSON_HEX_APOS(),
            JsonEncodeOption::JSON_PRESERVE_ZERO_FRACTION(),
            JsonEncodeOption::JSON_PRESERVE_ZERO_FRACTION(),
            JsonEncodeOption::JSON_NUMERIC_CHECK(),
        ]);
        self::assertEquals(
            JSON_FORCE_OBJECT | JSON_HEX_APOS | JSON_PRESERVE_ZERO_FRACTION | JSON_NUMERIC_CHECK,
            $encoder->getJsonOption()
        );

        $encoder->disableOption(JsonEncodeOption::JSON_HEX_APOS());
        self::assertEquals(
            JSON_FORCE_OBJECT | JSON_PRESERVE_ZERO_FRACTION | JSON_NUMERIC_CHECK,
            $encoder->getJsonOption()
        );
        $encoder->disableOptions([
            JsonEncodeOption::JSON_HEX_APOS(),
            JsonEncodeOption::JSON_PRESERVE_ZERO_FRACTION(),
            JsonEncodeOption::JSON_FORCE_OBJECT(),
        ]);
        self::assertEquals(JSON_NUMERIC_CHECK, $encoder->getJsonOption());
    }

    /**
     * 测试深度设置
     * @return void
     */
    public function testSetDepth()
    {
        $encoder = new Class2Json();
        $depth = mt_rand(10, 100);
        $encoder->setJsonDepth($depth);
        self::assertEquals($depth, $encoder->getJsonDepth());
    }

    public function testAutoTran()
    {
        $str = '{"demo_string":"abc"}';
        $pojo = new Pojo();
        $pojo->demoString = "abc";
        $pojo->ignore = uniqid();
        $o = new DefaultJsonValueFixer();
        $c = new CamelCase2UnderLine();
        $o->setPropertyNameTrans($c);
        self::assertEquals(spl_object_id($c), spl_object_id($o->getPropertyNameTrans()));
        $c = new Class2Json();
        $c->setFixer($o);
        $result = $c->jsonEncode($pojo);
        self::assertEquals($str, $result);
    }
}

# end of file
